package com.biboheart.brick.utils;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

import javax.imageio.ImageIO;

public class ImageUtils {
	private static ImageUtils iu = null;

	private ImageUtils() {
	}

	public static ImageUtils getInstance() {
		if (iu == null) {
			iu = new ImageUtils();
		}
		return iu;
	}

	/**
	 * 切割图片
	 * 
	 * @param os
	 *            切割后的输出流
	 * @param is
	 *            输入流
	 * @param type
	 *            文件的图片类型
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param width
	 *            宽度
	 * @param height
	 *            高度
	 */
	public void cropImg(OutputStream os, InputStream is, String type, int x, int y, int width, int height) {
		Image img;
		BufferedImage imgBuf;
		ImageFilter cropFilter;
		try {
			imgBuf = ImageIO.read(is);
			cropFilter = new CropImageFilter(x, y, width, height);
			img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(imgBuf.getSource(), cropFilter));
			BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			tag.getGraphics().drawImage(img, 0, 0, null);
			ImageIO.write(tag, type, os);
		} catch (IOException e) {
//			e.printStackTrace();
		} finally {
			try {
				if (os != null)
					os.close();
			} catch (IOException e) {
//				e.printStackTrace();
			}
			try {
				if (is != null)
					is.close();
			} catch (IOException e) {
//				e.printStackTrace();
			}
		}
	}

	/**
	 * 切割图片
	 * 
	 * @param oPath
	 *            切割后的输出文件路径
	 * @param is
	 *            输入流
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param width
	 *            宽度
	 * @param height
	 *            高度
	 * @return 成功输出文件地址，失败null
	 */
	public String cropImg(String oPath, InputStream is, int x, int y, int width, int height) {
		String type = oPath.substring(oPath.lastIndexOf(".") + 1);
		try {
			OutputStream os = new FileOutputStream(oPath);
			cropImg(os, is, type, x, y, width, height);
			return oPath;
		} catch (FileNotFoundException e) {
//			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 切割图片
	 * 
	 * @param oPath
	 *            输出文件
	 * @param iPath
	 *            输入文件名
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param width
	 *            宽度
	 * @param height
	 *            高度
	 * @return 成功输出文件地址，失败null
	 */
	public String cropImg(String oPath, String iPath, int x, int y, int width, int height) {
		String type = oPath.substring(oPath.lastIndexOf(".") + 1);
		try {
			OutputStream os = new FileOutputStream(oPath);
			InputStream is = new FileInputStream(iPath);
			cropImg(os, is, type, x, y, width, height);
			return oPath;
		} catch (FileNotFoundException e) {
//			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 切割图片自动根据输入的文件名转换为xxx_small.type
	 * 
	 * @param iPath
	 *            输入文件名
	 * @param x
	 *            x坐标
	 * @param y
	 *            y坐标
	 * @param width
	 *            宽度
	 * @param height
	 *            高度
	 * @return 成功输出文件地址，失败null
	 */
	public String cropImg(String iPath, int x, int y, int width, int height) {
		String type = iPath.substring(iPath.lastIndexOf(".") + 1);
		String sname = generatorSmallFileName(iPath);
		try {
			InputStream is = new FileInputStream(iPath);
			OutputStream os = new FileOutputStream(sname);
			cropImg(os, is, type, x, y, width, height);
			return sname;
		} catch (FileNotFoundException e) {
//			e.printStackTrace();
		}
		return null;
	}

	private String generatorSmallFileName(String name) {
		String fn = name.substring(0, name.lastIndexOf("."));
		return name.replace(fn, fn + "_small");
	}

	/**
	 * 转换图片操作
	 * 
	 * @param os
	 *            要转换图片的输出流
	 * @param is
	 *            要转换图片的输入流
	 * @param width
	 *            要压缩的宽度
	 * @param height
	 *            要压缩的高度
	 * @param proportion
	 *            是否进行等比例压缩
	 */
	public void compressImg(OutputStream os, InputStream is, int width, int height, boolean proportion) {
		compressImg(os, is, width, height, proportion, false);
	}

	/**
	 * 转换图片操作
	 * 
	 * @param os
	 *            要转换图片的输出流
	 * @param is
	 *            要转换图片的输入流
	 * @param width
	 *            要压缩的宽度
	 * @param height
	 *            要压缩的高度
	 * @param proportion
	 *            是否进行等比例压缩
	 * @param magnify
	 *            是否进行放大
	 */
	public void compressImg(OutputStream os, InputStream is, int width, int height, boolean proportion,
			boolean magnify) {
		BufferedImage img;
		try {
			img = ImageIO.read(is);
			if (null == img) {
				return;
			}
			int newWidth;
			int newHeight;
			int oldWidth = img.getWidth(null);
			int oldHeight = img.getHeight(null);
			boolean isWrite = false;
			if (!magnify) {
				boolean iw = width >= height;
				if (iw) {
					if (width > oldWidth)
						isWrite = true;
				} else {
					if (height > oldHeight)
						isWrite = true;
				}
				if (isWrite) {
					ImageIO.write(img, "JPEG", os);
					os.flush();
				}
			}
			if (!isWrite) {
				// 判断是否是等比缩放
				if (proportion) {
					// 为等比缩放计算输出的图片宽度及高度
					double rate1 = ((double) oldWidth) / (double) width + 0.1;
					double rate2 = ((double) oldHeight) / (double) height + 0.1;
					// 根据缩放比率大的进行缩放控制
					double rate = Math.min(rate1, rate2);
					newWidth = (int) (((double) img.getWidth(null)) / rate);
					newHeight = (int) (((double) img.getHeight(null)) / rate);
				} else {
					newWidth = width; // 输出的图片宽度
					newHeight = height; // 输出的图片高度
				}
				BufferedImage tag = new BufferedImage((int) newWidth, (int) newHeight, BufferedImage.TYPE_INT_RGB);
				tag.getGraphics().drawImage(img.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), 0, 0, null);
				ImageIO.write(tag, "JPEG", os);
			}
		} catch (IOException e) {
//			e.printStackTrace();
		} finally {
			try {
				if (os != null)
					os.close();
			} catch (IOException e) {
//				e.printStackTrace();
			}
			try {
				if (is != null)
					is.close();
			} catch (IOException e) {
//				e.printStackTrace();
			}
		}
	}

	/**
	 * 转换图片操作
	 * 
	 * @param outputFile
	 *            输出文件
	 * @param inputFile
	 *            输入文件
	 * @param width
	 *            要压缩的宽度
	 * @param height
	 *            要压缩的高度
	 * @param proportion
	 *            是否进行等比例压缩
	 * @return 成功输出文件地址，失败null
	 */
	public String compressImg(File outputFile, File inputFile, int width, int height, boolean proportion) {
		InputStream is;
		OutputStream os;
		try {
			is = new FileInputStream(inputFile);
			os = new FileOutputStream(outputFile);
			compressImg(os, is, width, height, proportion);
			return outputFile.getAbsolutePath();
		} catch (FileNotFoundException e) {
//			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 转换图片操作
	 * 
	 * @param outputFile
	 *            输出文件
	 * @param is
	 *            输入流
	 * @param width
	 *            要压缩的宽度
	 * @param height
	 *            要压缩的高度
	 * @param proportion
	 *            是否进行等比例压缩
	 * @return 成功输出文件地址，失败null
	 */
	public String compressImg(File outputFile, InputStream is, int width, int height, boolean proportion) {
		OutputStream os;
		try {
			os = new FileOutputStream(outputFile);
			compressImg(os, is, width, height, proportion);
			return outputFile.getAbsolutePath();
		} catch (FileNotFoundException e) {
//			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 转换图片操作
	 * 
	 * @param oPath
	 *            输出路径
	 * @param is
	 *            输入流
	 * @param width
	 *            要压缩的宽度
	 * @param height
	 *            要压缩的高度
	 * @param proportion
	 *            是否进行等比例压缩
	 * @return 成功输出文件地址，失败null
	 */
	public String compressImg(String oPath, InputStream is, int width, int height, boolean proportion) {
		OutputStream os;
		try {
			os = new FileOutputStream(oPath);
			compressImg(os, is, width, height, proportion);
		} catch (FileNotFoundException e) {
//			e.printStackTrace();
		}
		return oPath;
	}

	/**
	 * 转换图片操作
	 * 
	 * @param oPath
	 *            输出路径
	 * @param iPath
	 *            输入路径
	 * @param width
	 *            要压缩的宽度
	 * @param height
	 *            要压缩的高度
	 * @param proportion
	 *            是否进行等比例压缩
	 * @return 成功输出文件地址，失败null
	 */
	public String compressImg(String oPath, String iPath, int width, int height, boolean proportion) {
		InputStream is;
		OutputStream os;
		try {
			is = new FileInputStream(iPath);
			os = new FileOutputStream(oPath);
			compressImg(os, is, width, height, proportion);
		} catch (FileNotFoundException e) {
//			e.printStackTrace();
		}
		return oPath;
	}

	/**
	 * 获取图片宽度
	 * 
	 * @param is
	 *            输入的文件流
	 * @return 图片宽度
	 * @throws IOException
	 *             输入流错误
	 */
	public int getWidth(InputStream is) throws IOException {
		BufferedImage img;
		img = ImageIO.read(is);
		return img.getWidth(null);
	}

	/**
	 * 获取图片宽度
	 * 
	 * @param path
	 *            文件路径
	 * @return 图片宽度
	 */
	public int getWidth(String path) {
		InputStream is;
		try {
			is = Files.newInputStream(Paths.get(path));
			return getWidth(is);
		} catch (IOException e) {
//			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 获取图片宽度
	 * 
	 * @param file
	 *            图片文件
	 * @return 图片宽度
	 */
	public int getWidth(File file) {
		InputStream is;
		try {
			is = Files.newInputStream(file.toPath());
			return getWidth(is);
		} catch (IOException e) {
//			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 获取图片高度
	 * 
	 * @param is
	 *            输入流
	 * @return 图片调试
	 * @throws IOException
	 *             输入流错误
	 */
	public int getHeight(InputStream is) throws IOException {
		BufferedImage img;
		img = ImageIO.read(is);
		return img.getHeight(null);
	}

	/**
	 * 获取图片高度
	 * 
	 * @param path
	 *            图片路径
	 * @return 图片高度
	 */
	public int getHeight(String path) {
		InputStream is;
		try {
			is = Files.newInputStream(Paths.get(path));
			return getHeight(is);
		} catch (IOException e) {
//			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 获取图片高度
	 * 
	 * @param file
	 *            文件
	 * @return 图片高度
	 */
	public int getHeight(File file) {
		InputStream is;
		try {
			is = Files.newInputStream(file.toPath());
			return getHeight(is);
		} catch (IOException e) {
//			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 返回一个数组，第一个值是宽，第二个值是高
	 * 
	 * @param is
	 *            文件输入流
	 * @return 返回一个数组，第一个值是宽，第二个值是高
	 * @throws IOException
	 *             获取失败
	 */
	public int[] getWidthAndHeight(InputStream is) throws IOException {
		Image img;
		img = ImageIO.read(is);
		return new int[] { img.getWidth(null), img.getHeight(null) };
	}

	/**
	 * 返回一个数组，第一个值是宽，第二个值是高
	 * 
	 * @param path
	 *            文件路径
	 * @return 返回一个数组，第一个值是宽，第二个值是高
	 */
	public int[] getWidthAndHeight(String path) {
		InputStream is;
		try {
			is = Files.newInputStream(Paths.get(path));
			return getWidthAndHeight(is);
		} catch (IOException e) {
//			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 返回一个数组，第一个值是宽，第二个值是高
	 * 
	 * @param file
	 *            图片文件
	 * @return 返回一个数组，第一个值是宽，第二个值是高
	 */
	public int[] getWidthAndHeight(File file) {
		InputStream is;
		try {
			is = Files.newInputStream(file.toPath());
			return getWidthAndHeight(is);
		} catch (IOException e) {
//			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 图片添加水印
	 * 
	 * @param srcImgPath
	 *            需要添加水印的图片的路径
	 * @param outImgPath
	 *            添加水印后图片输出路径
	 * @param markContentColor
	 *            水印文字的颜色
	 * @param waterMarkContent
	 *            水印的文字
	 * @param right
	 *            水印距图片右边的像素
	 * @param bottom
	 *            水印距图片底边的像素
	 */
	public void mark(String srcImgPath, String outImgPath, Color markContentColor, String waterMarkContent, int right,
			int bottom) {
		try {
			// 读取原图片信息
			File srcImgFile = new File(srcImgPath);
			Image srcImg = ImageIO.read(srcImgFile);
			if (null == srcImg) {
				return;
			}
			int srcImgWidth = srcImg.getWidth(null);
			int srcImgHeight = srcImg.getHeight(null);
			// 加水印
			BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
			Graphics2D g = bufImg.createGraphics();
			g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
			Font font = new Font("宋体", Font.PLAIN, 50);
			g.setColor(markContentColor); // 根据图片的背景设置水印颜色
			g.setFont(font);
			int textWidth = g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0,
					waterMarkContent.length());
			int x = srcImgWidth - textWidth - right;
			int y = srcImgHeight - bottom;
			g.drawString(waterMarkContent, x, y);
			g.dispose();
			// 输出图片
			FileOutputStream outImgStream;
			String type;
			if (null != outImgPath && !outImgPath.isEmpty()) {
				outImgStream = new FileOutputStream(outImgPath);
				type = srcImgPath.substring(outImgPath.lastIndexOf(".") + 1);
			} else {
				outImgStream = new FileOutputStream(srcImgFile);
				String path = srcImgFile.getPath();
				type = path.substring(path.lastIndexOf(".") + 1);
			}
			ImageIO.write(bufImg, type, outImgStream);
			outImgStream.flush();
			outImgStream.close();
		} catch (Exception e) {
//			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param srcImgFile
	 *            需要添加水印的图片的文件
	 * @param outImgFile
	 *            添加水印后图片输出文件
	 * @param markContentColor
	 *            水印文字的颜色
	 * @param waterMarkContent
	 *            水印的文字
	 * @param right
	 *            水印距图片右边的像素
	 * @param bottom
	 *            水印距图片底边的像素
	 */
	public void mark(File srcImgFile, File outImgFile, Color markContentColor, String waterMarkContent, int right,
			int bottom) {
		if (null == srcImgFile) {
			return;
		}
		try {
			// 读取原图片信息
			Image srcImg = ImageIO.read(srcImgFile);
			if (null == srcImg) {
				return;
			}
			int srcImgWidth = srcImg.getWidth(null);
			int srcImgHeight = srcImg.getHeight(null);
			// 加水印
			BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
			Graphics2D g = bufImg.createGraphics();
			g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
			Font font = new Font("宋体", Font.PLAIN, 50);
			g.setColor(markContentColor); // 根据图片的背景设置水印颜色
			g.setFont(font);
			int textWidth = g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0,
					waterMarkContent.length());
			int x = srcImgWidth - textWidth - right;
			int y = srcImgHeight - bottom;
			g.drawString(waterMarkContent, x, y);
			g.dispose();
			// 输出图片
			FileOutputStream outImgStream;
			String type;
			if (null != outImgFile) {
				outImgStream = new FileOutputStream(outImgFile);
				String path = outImgFile.getPath();
				type = path.substring(path.lastIndexOf(".") + 1);
			} else {
				outImgStream = new FileOutputStream(srcImgFile);
				String path = srcImgFile.getPath();
				type = path.substring(path.lastIndexOf(".") + 1);
			}
			ImageIO.write(bufImg, type, outImgStream);
			outImgStream.flush();
			outImgStream.close();
		} catch (Exception e) {
//			e.printStackTrace();
		}
	}
}
